
import { genCodeForXMLTemplate, }  from './Compiler.js';
import { createVNodeByCode } from './VNode.js';
import { mountVNodeToBody } from './Renderer.js';

export class PageDelegate
{
    constructor(page) {
        this.page = page;

        function noop () {}
        this.onInitStart = noop;
        this.onInited = noop;
        this.onPageEvent = noop;
        this.onReady = noop;
    }
}

//Page class is designed for running in browser, not limit to mini-program web view control
export class Page {
    constructor(elem, data, template, css, delegate) {
        this.elem = elem || document.body;
        this.data = data;
        this.css = css;
        this.vnode = null;
        this.ready = false; //set ready to true first time after rendering node to dom
        this.eventHandlers = [];
        this.delegate = delegate || null;

        if (typeof template === 'function') {
            //precompiled function
            this.renderCode = null;
        }
        else {
            this.template = template;
        }
    }

    getData() {
        return this.data;
    }

    setData(newData) {
        if (!this.data) {
            this.data = newData;
        }
        else {
            this.data = this._patchData(this.data, newData);
        }
        this._update();
    }

    static compileXMLTemplate(template) {
        return genCodeForXMLTemplate(template);
    }

    //called by UIEventHandler onEvent
    onUIEvent(event) {
        if (!event) {
            console.warn('Page.onUIEvent, eventHandler is empty');
            return;
        }

        if (this.delegate) {
            //if delegate exists, dispatch event to delegate
            this.delegate.onPageEvent(event);
        }
        else {
            if (event.callback in this.data) {
                if (typeof this.data[event.callback] !== 'function') {
                    console.warn("event handler '" + event.callback +"' is not a function");
                }
                else {
                    this.data[event.callback](event.data);
                }
            }
            else {
                console.warn("event handler '" + eventHandler.target + "' not found");
            }
        }
    }

    _patchData(oldData, newData) {
        Object.keys(newData).forEach((key)=>{
            oldData[key] = newData[key];
        });
        return oldData;
    }

    create() {
        return this._init();
    }

    _init() {
        if (this.delegate) {
            this.delegate.onInitStart();
        }

        if (!this.renderCode && this.template) {
            this.renderCode = Page.compileXMLTemplate(this.template);
        }
        else {
            console.warn("Page init failed, either renderCode or template should be provided");
            return;
        }

        if (this.data) {
            //allow set data after initializing
            this.setData(this.data);
        }

        //notify inited
        if (this.delegate) {
            this.delegate.onInited();
        }
    }

    _update() {
        let root = createVNodeByCode(this.data, this.renderCode);
        this.vnode = root;
        if (!root) {
            console.warn("update page, root is null");
            return;
        }

        this._clearBody();
        mountVNodeToBody(this, this.elem, this.vnode);
        if (!this.ready) {
            console.log("page is ready");
            if (this.delegate) {
                this.delegate.onReady()
            }
        }
    }

    _clearBody() {
        document.body.childNodes.forEach(function(node) {
            document.body.removeChild(node);
        });
    }
}



